package com.hbzhit.modules.sys.service.impl;

import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hbzhit.common.exception.RRException;
import com.hbzhit.common.extension.BaseServiceImpl;
import com.hbzhit.common.utils.Constant;
import com.hbzhit.common.utils.PoiUtils;
import com.hbzhit.common.utils.ShiroUtils;
import com.hbzhit.common.validator.ValidatorUtils;
import com.hbzhit.common.validator.group.ImportGroup;
import com.hbzhit.config.CacheConfig;
import com.hbzhit.modules.sys.dao.SysDictValDao;
import com.hbzhit.modules.sys.dao.SysOrgDao;
import com.hbzhit.modules.sys.dao.SysUserDao;
import com.hbzhit.modules.sys.entity.SysMenuEntity;
import com.hbzhit.modules.sys.entity.SysOrgEntity;
import com.hbzhit.modules.sys.entity.SysUserEntity;
import com.hbzhit.modules.sys.service.SysUserRoleService;
import com.hbzhit.modules.sys.service.SysUserService;
import lombok.AllArgsConstructor;
import org.activiti.engine.IdentityService;
import org.activiti.engine.identity.User;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


/**
 * 系统用户
 *
 * @author Mark sunlightcs@gmail.com
 */
@Service("sysUserService")
@AllArgsConstructor
public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntity> implements SysUserService {

	private final SysUserRoleService sysUserRoleService;
	private final IdentityService identityService;
	private final SysOrgDao sysOrgDao;
	private final SysDictValDao valDao;

	@Override
	public SysUserEntity getById(Serializable id) {
		SysUserEntity user = super.getById(id);
		//获取用户所属的角色列表
		List<Long> roleIdList = sysUserRoleService.queryRoleIdList(user.getId());
		user.setRoleIdList(roleIdList);
		return user;
	}

	@Override
	public List<String> queryAllPerms(Long userId, String prop) {
		return baseMapper.queryAllPerms(userId, prop);
	}

	@Override
	public List<Long> queryAllMenuId(Long userId) {
		return baseMapper.queryAllMenuId(userId);
	}

	@Override
	public List<SysMenuEntity> queryAllMenu(Long userId, String prop) {
		return baseMapper.queryAllMenu(userId, prop);
	}

	@Override
	public SysUserEntity queryByUserName(String username) {
		SysUserEntity user = baseMapper.queryByUserName(username);
		if (user == null) {
			return null;
		}
		//获取用户所属的角色列表
		List<Long> roleIdList = sysUserRoleService.queryRoleIdList(user.getId());
		user.setRoleIdList(roleIdList);
		return user;
	}

	@Override
	public SysUserEntity queryByMobile(String mobile) {
		return super.getOne(new QueryWrapper<SysUserEntity>().eq("mobile", mobile), false);
	}

	@Override
	public SysUserEntity queryByOpenId(String openid) {
		return super.getOne(new QueryWrapper<SysUserEntity>().eq("openid", openid), false);
	}

	@Override
	public List<SysUserEntity> listAll() {
		return this.list(new LambdaQueryWrapper<SysUserEntity>()
				.eq(SysUserEntity::getIsDel, Constant.INT_N)
				.or()
				.eq(SysUserEntity::getIsDel, Constant.INT_Y)
		);
	}

	/**
	 * 保存流程引擎用户
	 * @param user 系统用户对象
	 */
	private void saveActUser(SysUserEntity user) {
		identityService.deleteUser(String.valueOf(user.getId()));
		User actUser = identityService.newUser(String.valueOf(user.getId()));
		actUser.setFirstName(user.getUsername());
		actUser.setLastName(user.getRealName());
		identityService.saveUser(actUser);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean save(SysUserEntity user) {
		this.saveValid(user);
		if (StrUtil.isNotBlank(user.getPassword())) {
			//sha256加密
			String salt = RandomStringUtils.randomAlphanumeric(20);
			user.setPassword(new Sha256Hash(user.getPassword(), salt).toHex());
			user.setSalt(salt);
		}
		boolean rt = super.save(user);

		//同步流程引擎用户
		saveActUser(user);

		//保存用户与角色关系
		sysUserRoleService.saveOrUpdate(user.getId(), user.getRoleIdList());

		//更新缓存
		CacheConfig.userCache.put(user.getId(), user);
		
		return rt;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateById(SysUserEntity user) {
		SysUserEntity oldUser = super.getById(user.getId());
		this.saveValid(user);
		if(StringUtils.isBlank(user.getPassword()) || ObjectUtil.equals(oldUser.getPassword(), user.getPassword())){
			user.setPassword(null);
		}else{
			//sha256加密
			String salt = StrUtil.isBlank(user.getSalt()) ? RandomStringUtils.randomAlphanumeric(20) : user.getSalt();
			user.setPassword(new Sha256Hash(user.getPassword(), salt).toHex());
			user.setSalt(salt);
		}
		boolean rt = super.updateById(user);

		//同步流程引擎用户
		saveActUser(user);

		//保存用户与角色关系
		sysUserRoleService.saveOrUpdate(user.getId(), user.getRoleIdList());

		//更新缓存
		CacheConfig.userCache.put(user.getId(), user);
		
		return rt;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteBatch(Long[] ids) {
		this.delValid(ids);
		this.removeByIds(Arrays.asList(ids));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteBatchUser(Long[] ids) {
		this.delValid(ids);

		List<Long> idList = Arrays.asList(ids);
		List<SysUserEntity> users = this.listByIds(idList);
		users.forEach(user -> {
			// 用户已生成人员，则取消用户，否则删除
			if (user.getIsMember() == Constant.INT_Y) {
				user.setIsAdmin(Constant.INT_N);
				super.updateById(BeanUtil.toBean(user, SysUserEntity.class));
			} else {
				this.removeById(user.getId());
			}
		});
	}

	@Override
	public boolean updatePassword(Long userId, String password, String newPassword) {
		SysUserEntity userEntity = new SysUserEntity();
		userEntity.setPassword(newPassword);
		return this.update(userEntity,
				new QueryWrapper<SysUserEntity>().lambda()
						.eq(SysUserEntity::getId, userId)
						.eq(SysUserEntity::getPassword, password)
		);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateBatch(SysUserEntity user, Long[] ids) {
		List<Long> idList = Arrays.asList(ids);

		idList.forEach(id -> {
			SysUserEntity nowUser = new SysUserEntity();
			BeanUtil.copyProperties(user, nowUser);
			nowUser.setId(id);
			this.updateById(nowUser);
		});
	}

	@Override
	public void changeOrgBatch(Long[] userIds, Long orgId) {
		this.update(new LambdaUpdateWrapper<SysUserEntity>()
				.set(SysUserEntity::getOrgId, orgId)
				.in(SysUserEntity::getId, Arrays.asList(userIds))
		);
	}

	@Override
	public void bindOpenId(Map<String, Object> params) {
		String username = (String) params.get("username");
		String password = (String) params.get("password");
		String openId = (String) params.get("openId");
		if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password) || StringUtils.isEmpty(openId)) {
			throw new RRException("参数缺失");
		}
		SysUserEntity user = getOne(new QueryWrapper<SysUserEntity>().lambda().eq(SysUserEntity::getUsername, username));
		if (user == null) {
			throw new RRException("账号错误");
		}
		String passwordSha = new Sha256Hash(password, user.getSalt()).toHex();
		if (!passwordSha.equals(user.getPassword())) {
			throw new RRException("密码错误");
		}
		if (StringUtils.isNotEmpty(user.getOpenid()) && !openId.equals(user.getOpenid())) {
			throw new RRException("该人员已绑定其他微信号");
		}
		this.update(new LambdaUpdateWrapper<SysUserEntity>()
				.eq(SysUserEntity::getUsername, username)
				.set(SysUserEntity::getOpenid, openId)
		);
	}

	@Override
	public void unbindOpenId(SysUserEntity user) {
		this.update(new LambdaUpdateWrapper<SysUserEntity>()
				.eq(SysUserEntity::getUsername, user.getUsername())
				.set(SysUserEntity::getOpenid, "")
		);
	}

	@Override
	public ExcelImportResult<SysUserEntity> importExcel(InputStreamSource source) throws Exception {
		//执行导入
		ExcelImportResult<SysUserEntity> result = PoiUtils.importExcel(source.getInputStream(), this.getEntityClass(), this.importVerifyHandler());

		// 批量写入数据库
		this.saveBatch(result.getList());

		return result;
	}

	/**
	 * 用户保存校验
	 * @param entity 用户对象
	 */
	private void saveValid(SysUserEntity entity) {
		// 判断编码是否重复
		int count = this.count(new QueryWrapper<SysUserEntity>().lambda()
				.eq(SysUserEntity::getUsername, entity.getUsername())
				.ne(entity.getId() != null, SysUserEntity::getId, entity.getId()));
		if (count > 0) {
			throw new RRException("编码已存在，不能保存");
		}
	}

	/**
	 * 用户删除校验
	 * @param ids 用户id集合
	 */
	private void delValid(Long[] ids) {
		if(ArrayUtils.contains(ids, Constant.SUPER_ADMIN)){
			throw new RRException("系统管理员不能删除");
		}
		if(ArrayUtils.contains(ids, ShiroUtils.getUserId())){
			throw new RRException("当前用户不能删除");
		}

	}

	private IExcelVerifyHandler<SysUserEntity> importVerifyHandler() {
		return user -> {
			ExcelVerifyHandlerResult result = new ExcelVerifyHandlerResult(true);
			// 注解校验
			String validMsg = ValidatorUtils.validate(user, ImportGroup.class);
			if (validMsg != null) {
				result.setSuccess(false);
				result.setMsg(validMsg);
				return result;
			}
			/*机构校验及转换*/
			SysOrgEntity org = sysOrgDao.selectOne(new LambdaQueryWrapper<SysOrgEntity>()
							.eq(SysOrgEntity::getOrgName,StrUtil.trim(user.getOrgName()))
			);
			if (org == null) {
				result.setSuccess(false);
				result.setMsg(StrUtil.format("所属机构【{}】不存在，请修正或创建。", user.getOrgName()));
				return result;
			}
			user.setOrgId(org.getId());
			/*部门校验及转换*/
			SysOrgEntity dept = sysOrgDao.selectOne(new LambdaQueryWrapper<SysOrgEntity>()
							.eq(SysOrgEntity::getOrgName,StrUtil.trim(user.getDeptName()))
							.likeRight(SysOrgEntity::getOrgCode, org.getOrgCode())
			);
			if (dept == null) {
				result.setSuccess(false);
				result.setMsg(StrUtil.format("机构【{}】下所属部门【{}】不存在，请修正或创建。", org.getOrgName(), user.getDeptName()));
				return result;
			}
			user.setDeptId(dept.getId());
			// 判断编码是否重复
			int count = this.count(new QueryWrapper<SysUserEntity>().lambda()
					.eq(SysUserEntity::getUsername, user.getUsername())
					.ne(user.getId() != null, SysUserEntity::getId, user.getId()));
			if (count > 0) {
				result.setSuccess(false);
				result.setMsg(StrUtil.format("身份证号【{}】已存在，不能重复创建。", user.getUsername()));
				return result;
			}
			// 人员标识
			user.setIsMember(Constant.INT_Y);

			return result;
		};
	}
	
}
